package com.renfei.multimediatask.ui.task9.encodec;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
import android.os.Debug;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.renfei.multimediatask.ui.task7.AudioAacEncodecActivity;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;

public class MediaAudioEncoder extends MediaEncoder implements Runnable {


    public MediaAudioEncoder(MediaManager mediaManager) {
        super(mediaManager);
    }

    private static final boolean Debug = false;
    private static final String TAG = "MediaAudioEncoder";

    //是否正在录制
    private boolean isAudioRecording = false;

    private AudioRecord audioRecord;
    private int audioSource;   //音频来源
    private int bufferSizeInBytes;   //最小缓存大小

    private int sampleRateInHz = 44100;   //采样率
    private int channelConfig = AudioFormat.CHANNEL_IN_MONO;   //声道数
    private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;   //采样格式(存储位数， 8位 16位)


    //编码
    private MediaCodec audioEncode;
    private MediaCodec.BufferInfo audioBufferInfo;

    private long audioPts = 0;
    private int encodecCount = 0;

    private int audioTrackIndex = -1;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void run() {
        Log.e(TAG, "mMediaAudioEncoder : thread  is runing ");

        audioTrackIndex = -1;

        if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
            if (Debug) Log.e("RecordThread ", audioRecord.getState() + "");
            return;
        }
        audioRecord.startRecording();
        isAudioRecording = true;
        if (Debug) Log.e(TAG, "音频录制开始 ");
        while (isAudioRecording) {

            //获取数据
            ByteBuffer audioBuffer = ByteBuffer.allocateDirect(bufferSizeInBytes);
            audioBuffer.clear();
            int resultLen = audioRecord.read(audioBuffer, bufferSizeInBytes);

            //编码

            //处理输入
            int inputBufferIndex = audioEncode.dequeueInputBuffer(0);
            if (inputBufferIndex >= 0) {
                ByteBuffer inputBuffer = audioEncode.getInputBuffer(inputBufferIndex);
                inputBuffer.clear();
                inputBuffer.put(audioBuffer);


                if (resultLen > 0) {
                    audioEncode.queueInputBuffer(
                            inputBufferIndex, 0, resultLen, getAudioPts(encodecCount),
                            0
                    );
                } else {//数据小于0  发送结束标志
                    audioEncode.queueInputBuffer(inputBufferIndex, 0, 0, getAudioPts(encodecCount), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                }
                encodecCount++;
            }

            //处理输出

            int outputBUfferIndex = audioEncode.dequeueOutputBuffer(audioBufferInfo, 0);
            if (outputBUfferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                if (null != managerWeak.get().mMediaMuxer) {
                    audioTrackIndex =  managerWeak.get().addTrack(audioEncode.getOutputFormat());
                    Log.e(TAG, TAG + "    输出格式已更改: ");
                    managerWeak.get().start();
                }
            } else {
                while (outputBUfferIndex > 0) {
                    if ( managerWeak.get().isMuxerStarted) {
                        ByteBuffer outputBuffer = audioEncode.getOutputBuffers()[outputBUfferIndex];

                        outputBuffer.position(audioBufferInfo.offset);
                        outputBuffer.limit(audioBufferInfo.offset + audioBufferInfo.size);

                        audioBufferInfo.presentationTimeUs = getAudioOutputPTSUs();

                        Log.e(TAG,"audioBufferInfo.presentationTimeUs   "+audioBufferInfo.presentationTimeUs     );
                        Log.e(TAG,"audioBufferInfo.size                 "+audioBufferInfo.size                   );
                        Log.e(TAG,"audioBufferInfo.flags                "+audioBufferInfo.flags                  );
                        Log.e(TAG,"audioBufferInfo.offset               "+audioBufferInfo.offset                 );

                        managerWeak.get().writeSampleData(audioTrackIndex, outputBuffer, audioBufferInfo);
                        audioOutputPTSUs = audioBufferInfo.presentationTimeUs;

                        audioEncode.releaseOutputBuffer(outputBUfferIndex, false);
                        outputBUfferIndex = audioEncode.dequeueOutputBuffer(audioBufferInfo, 0);
                    } else {
                        Log.e(TAG, "isMediaMuxerStart:  mediaMuxer is not start");
                    }
                }
            }
        }
    }

    @Override
    void release() {
        if (audioRecord != null && audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
            audioRecord.stop();
            audioRecord.release();
            audioRecord = null;
        }
        if (null != audioEncode) {
            audioEncode.stop();
            audioEncode.release();
            audioEncode = null;
        }
        super.release();

    }

    private long getAudioPts(int size) {
        audioPts += (long) (1.0 * size / (sampleRateInHz * 2 * 2) * 1000000.0);

        return audioPts;
    }


    protected long audioOutputPTSUs = 0;

    protected long getAudioOutputPTSUs() {
        long result = System.nanoTime() / 1000L;
        if (result < audioOutputPTSUs)
            result = (audioOutputPTSUs - result) + result;
        return result;
    }


    @Override
    void prepare() {
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
        audioRecord = new AudioRecord(
                audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes
        );
        Log.e("RecordThread 初始化时 ", audioRecord.getState() + "");


        audioBufferInfo = new MediaCodec.BufferInfo();
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
        try {
            audioEncode = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);

            MediaFormat audioFormat = MediaFormat.createAudioFormat(
                    MediaFormat.MIMETYPE_AUDIO_AAC,
                    sampleRateInHz,
                    1
            );
            audioFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
            audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
            audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSizeInBytes);
            audioEncode.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            audioEncode.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Log.e(TAG, "MediaAudioEncoder:  prepare  finished");
    }


    @Override
    void startRecording() {
        super.startRecording();
        new Thread(this, getClass().getSimpleName()).start();

        Log.e(TAG, "MediaAudioEncoder: startRecording");
    }

    @Override
    void stopRecording() {
        isAudioRecording = false;
        super.stopRecording();

    }


}
